<template>
  <div class="innerContainer">
    <common-title :text="`设备详情 （ ${searchForm.name} ）`">
      <template #expand>
        <el-button type="primary" plain size="mini" @click="router.go(-1)">返回上一级</el-button>
      </template>
    </common-title>
    <div class="innerPane">
      <div class="filterArea">
        <el-form :model="filterForm" class="demo-form-inline" style="width: 100%;">
          <el-form-item inline label="历史数据">
            <div class="block datetime-picker">
              <el-date-picker v-model="searchForm.timeRange" tart-placeholder="起始时间" end-placeholder="结束时间"
                type="datetimerange" @change="handleTimeChange" />
            </div>

            <el-button type="primary" @click="getHistoryData" :disabled="!searchForm.timeRange ||
              !searchForm.timeRange[0] ||
              !searchForm.timeRange[1]
              ">查看数据</el-button>
            <el-button type="primary" :disabled="!searchForm.timeRange ||
              !searchForm.timeRange[0] ||
              !searchForm.timeRange[1] ||
              onFileLoading
              " :loading="onFileLoading" @click="handleDownload">下载数据</el-button>

            <div style="position: absolute;right: 50px; ">
              <el-tag type="primary" v-if="lastHeartInfo" effect="plain" style="margin-left: 10px">电量: {{
                lastHeartInfo.bat_power }}</el-tag>


              <el-tag type="warning" v-if="lastHeartInfo" effect="plain" style="margin-left: 10px">电压: {{
                lastHeartInfo.vbat
              }}</el-tag>

              <el-tag type="success" v-if="lastHeartInfo" effect="plain" style="margin-left: 10px">温度: {{
                lastHeartInfo.temp
              }}</el-tag>

              <el-tag type="info" v-if="lastHeartInfo" effect="plain" style="margin-left: 10px">湿度: {{
                lastHeartInfo.humi
              }}</el-tag>

            </div>

          </el-form-item>

          <el-form-item inline label="显示点数">
            <div class="block">
              <el-input placeholder="点数" v-model="searchForm.showPointNum" style="width: 220px"
                :readonly="onRefresh"></el-input>
            </div>
            <el-button type="primary" @click="handleLastData" plain :disabled="onRefresh">最新数据</el-button>
            <el-button type="success" plain v-if="!onRefresh" @click="openConnect">开始持续刷新</el-button>
            <el-button type="warning" plain v-else @click="closeConnect">关闭持续刷新</el-button>
          </el-form-item>

          <el-form-item inline label="单日数据">
            <div class="block">
              <el-date-picker v-model="searchForm.downloadDay" type="date" placeholder="时间" format="YYYY-MM-DD"
                value-format="YYYY-MM-DD" />
            </div>
            <el-button type="primary" plain :disabled="!searchForm.downloadDay || onDayLoading" :loading="onDayLoading"
              @click="handlerDayDownload">单日下载</el-button>

            <!-- <el-button-group class="ml-2" style="margin-left: 15px;">
              <el-button type="success" plain :icon="Share">零点校准</el-button>
              <el-button type="warning" plain :icon="Delete">零点复原</el-button>
            </el-button-group> -->
          </el-form-item>

        </el-form>
      </div>

      <div class="container">
        <el-empty v-if="chartData && !chartData.length"></el-empty>
        <el-scrollbar>
          <div class="lineChart" v-for="(item, index) in chartData" :id="'linechart' + item.label" :key="item.label">
          </div>
        </el-scrollbar>
      </div>
    </div>
  </div>
</template>

<script setup>
import CommonTitle from "@/components/CommonTitle.vue";

import { onMounted, onUnmounted, ref, nextTick, computed } from "vue";
import { ElMessage } from "element-plus";

import format from "date-format";

import {
  equipmentLastInfo,
  equipmentLastHeartInfo,
  equipmentHistoryInfo,
  downloadDay,
  downloadFile, equipmentAdList, baseSeviceHeart
} from "../../utils/requests";

import { BASE_URL, BASE_PRE } from "@/utils/base.js";

import * as echarts from "echarts";

import { useRouter } from "vue-router";


import { storage } from '@/utils/storage.js';
import { tr } from "element-plus/es/locales.mjs";


const router = useRouter();

const searchForm = ref({
  sn: null,
  name: null,
  timeRange: "",
  showPointNum: 1000,
  downloadDay: null,
});

let chartData = ref();

let chartObj = {};

let onRefresh = ref(false);

// Dom 挂载之后
onMounted(async () => {
  searchForm.value.sn = router.currentRoute.value.query.code;

  searchForm.value.name = router.currentRoute.value.query.name;

  window.addEventListener("resize", resize);
  handleLastData();
});

let socket = null;
// 心跳间隔：30 秒（可调）
const HEARTBEAT_INTERVAL = 30_000;
let heartbeatTimer = null;

const startHeartbeat = () => {
  heartbeatTimer = setInterval(() => {
    if (socket.readyState === WebSocket.OPEN) {
      socket.send(''); // 发任意字符串即可，后端可忽略

      baseSeviceHeart();
    }
  }, HEARTBEAT_INTERVAL);
}

const stopHeartbeat = () => {
  clearInterval(heartbeatTimer);
}

const openConnect = () => {
  const socketUrl =
    BASE_URL + BASE_PRE + "/ws/" + storage.get("be-token") + "_" + router.currentRoute.value.query.id;
  if (socket != null) {
    socket.close();
    socket = null;
  }
  socket = new WebSocket(socketUrl);

  // 记录页面可见性
  let wasHidden = false;

  // 监听页面可见性变化
  const handleVisibilityChange = () => {
    if (document.hidden) {
      wasHidden = true;
    } else if (wasHidden && onRefresh.value) {
      // 页面从后台切回前台，重新建立 websocket 连接
      wasHidden = false;
      closeConnect();
      // 重新建立连接
      setTimeout(() => {
        openConnect();
      }, 500);
    }
  };
  document.addEventListener("visibilitychange", handleVisibilityChange);

  // 打开事件
  socket.onopen = function () {
    console.log("websocket已打开");
    setTimeout(() => {
      startRefresh();

      startHeartbeat();
    }, 500);
  };
  // 获得消息事件
  socket.onmessage = function (msg) {
    if (!onRefresh.value) return;

    let msgData = JSON.parse(msg.data);

    if (Object.hasOwn(msgData, 'data')) {

      // 第一次加载
      if (!chartData.value) {
        chartData.value = msgData.data;

        chartData.value.forEach((item) => {
          chartObj["chart" + item.label] = {
            data: item,
          };
        });


        setTimeout(() => {
          for (let key in chartObj) {
            chartObj[key].ele = echarts.init(
              document.getElementById("line" + key),
            );
            setChart(chartObj[key].ele, chartObj[key].data);
          }
        }, 0);
      } else {
        // 增加数据
        chartData.value.forEach((item, index) => {


          item.time = [...item.time, ...msgData.data[index].time];
          item.data = [...item.data, ...msgData.data[index].data];
          item.out = { ...item.out, ...msgData.data[index].out };

          if (item.time.length > searchForm.value.showPointNum) {
            item.time = item.time.slice(-searchForm.value.showPointNum);
            item.data = item.data.slice(-searchForm.value.showPointNum);
          }
        });

        chartData.value.forEach((item) => {
          chartObj["chart" + item.label].data = item;
        });

        for (let key in chartObj) {
          updateChart(chartObj[key].ele, chartObj[key].data);
        }
      }
    } else if (Object.hasOwn(msgData, 'heart')) {
      lastHeartInfo.value = msgData['heart'];
    }

  };
  // 关闭事件
  socket.onclose = function () {
    console.log("websocket已关闭");

    stopHeartbeat();

    document.removeEventListener("visibilitychange", handleVisibilityChange);
  };
  // 发生了错误事件
  socket.onerror = function () {
    console.log("websocket发生了错误");

    stopHeartbeat();

    console.log("关闭心跳");

  };
};

const closeConnect = () => {
  if (socket != null) {
    socket.close();
    socket = null;
  }

  onRefresh.value = false;
};
const startRefresh = () => {
  resetData();
  var postData = {
    method: "mqtt.listen",
    cond: {
      snCode: searchForm.value.sn,
      uid: storage.get("be-token") + "_" + router.currentRoute.value.query.id,
    },
    toUid: storage.get("be-token") + "_" + router.currentRoute.value.query.id,
  };

  socket.send(JSON.stringify(postData));

  onRefresh.value = true;
};

const resetData = () => {
  chartData.value = null;
  chartObj = {};
};
// 在组件销毁时销毁图表实例
onUnmounted(() => {
  closeConnect();
  window.removeEventListener("resize", resize);
});

const MAX_HOURS = 2;

const handleTimeChange = (dates) => {
  if (!dates || dates.length < 2) {
    return;
  }

  const [start, end] = dates;
  const startTime = new Date(start);
  const endTime = new Date(end);
  const diffHours = (endTime - startTime) / (1000 * 60 * 60);

  // 检查时间跨度
  if (diffHours > MAX_HOURS) {
    // 计算新的结束时间（开始时间 + 10小时）
    const newEndTime = new Date(startTime);
    newEndTime.setHours(startTime.getHours() + MAX_HOURS);

    // 更新选择器值
    searchForm.value.timeRange = [start, newEndTime];
    ElMessage.warning(`数据查看的最大时间跨度为${MAX_HOURS}小时`);
  }
};

/**
 * 查看数据
 */
const getHistoryData = async () => {
  const [start, end] = searchForm.value.timeRange;
  let current = new Date(start).getTime();
  const endTime = new Date(end).getTime();
  const interval = 60 * 1000; // 1 minute in ms

  // 清空旧图表
  chartData.value = [];
  chartObj = {};

  while (current < endTime) {
    const next = Math.min(current + interval, endTime);
    // eslint-disable-next-line no-await-in-loop
    const data = await equipmentHistoryInfo({
      sn: searchForm.value.sn,
      stime: format("yyyy-MM-dd hh:mm:ss", new Date(current)),
      etime: format("yyyy-MM-dd hh:mm:ss", new Date(next)),
    });

    if (Array.isArray(data) && data.length) {
      // 按 label 合并
      data.forEach(item => {
        let target = chartData.value.find(d => d.label === item.label);
        if (!target) {
          // 新增分组
          target = {
            label: item.label,
            time: [],
            data: [],
            out: item.out
          };
          chartData.value.push(target);
        }
        target.time = target.time.concat(item.time);
        target.data = target.data.concat(item.data);
      });

      // 渲染/更新图表
      await nextTick();

      chartData.value.forEach((item) => {
        if (!chartObj[item.label]) {
          // 新建图表
          const ele = echarts.init(document.getElementById("linechart" + item.label));
          chartObj[item.label] = { ele, data: item };
          setChart(ele, item);
        } else {
          // 更新图表
          chartObj[item.label].data = item;

          updateChart(chartObj[item.label].ele, item, false);
        }
      });
    }
    current = next;
  }
};

// 修改 updateChart 方法
const updateChart = (ele, data, isReset = false) => {
  if (isReset) {
    setChart(ele, data, true);
  } else {
    setChart(ele, data, false);
  }
};

const lastHeartInfo = ref({})

/**
 * 最新数据
 */
const handleLastData = async () => {
  resetData();
  equipmentLastInfo({ sn: searchForm.value.sn }).then((data) => {
    if (Object.hasOwn(data, 'data')) {

      createData(data['data']);
    }
  });

  equipmentLastHeartInfo({ sn: searchForm.value.sn }).then((data) => {
    if (Object.hasOwn(data, 'heart')) {

      lastHeartInfo.value = data['heart'];
    }
  });
};




const createData = (data) => {
  chartData.value = data;

  if (!chartData.value.length) return;

  // 构建chart
  chartData.value.forEach((item) => {
    chartObj["chart" + item.label] = {
      data: item,
    };
  });

  setTimeout(() => {
    for (let key in chartObj) {
      chartObj[key].ele = echarts.init(document.getElementById("line" + key));
      setChart(chartObj[key].ele, chartObj[key].data);
    }
  }, 0);
};



const setChart = (ele, data, iclear) => {

  var series = [
    {
      type: "line",
      large: true,
      progressive: 1000, // 分片渲染（每3000点渲染一次）
      clip: true,
      showSymbol: false,
      lineStyle: {
        width: 0.8,
        color: "#0089ff",
        opacity: 0.9, // 轻微透明提升渲染性能
        cap: "butt",
      }, // 直线端点样式（性能最优） },
      label: {
        show: false,
      },
      blendMode: "source-over", // 避免透明通道计算
      itemStyle: {
        color: "#0089ff",
      },
      data: data.data,
    },
  ];
  var options = {
    legend: {
      show: true,
      right: 0,
    },
    tooltip: {
      show: true,
      trigger: "axis",
    },
    title: [{
      text: data.label,
      textAlign: "center",
      left: 80,
      top: 10,
      textStyle: { fontSize: 16, fontWeight: 'bold' }
    },
    {
      text: data.out?.length > 0 ? `均值: ${data.out.avg.toFixed(2)}    标准差: ${data.out.std.toFixed(2)}    中位数: ${data.out.median.toFixed(2)}    有效值: ${data.out.rms.toFixed(2)}` : '',
      left: 'center',
      top: 10,
      textStyle: { fontSize: 12 }
    }],
    grid: {
      left: "8%",
      right: 80,
      bottom: "12%",
      top: 50,
      // containLabel: true,
    },
    dataZoom: [
      {
        type: "inside",
        throttle: 200, // 操作节流200ms
        realtime: false, // 关闭实时更新
        zoomLock: false,
        start: 0,
        end: 100,
      },
      {
        type: "slider",
        realtime: false, // 重要！必须关闭实时渲染
        brushSelect: false,
        throttle: 300,
        height: 15,
        bottom: 0,
      },
    ],
    animation: false,
    xAxis: [
      {
        type: "category",
        name: "时间（s）",
        nameGap: 8,
        splitLine: {
          show: false,
        },
        axisLine: {
          show: true,
          lineStyle: {
            width: 1,
            color: "#aaa",
          },
        },
        axisTick: {
          show: false,
        },
        data: data.time,
        axisLabel: {
          show: true,
          interval: Math.max(5, Math.floor(data.time.length / 30)),
          // rotate: 30,
          formatter: function (value) {

            return value.replace(/\s+/g, "\n");
          },
          textStyle: {
            color: "#666",
            fontSize: 14,
          },
        },
      },
    ],
    yAxis: [
      {
        type: "value",
        nameLocation: "end",
        splitLine: {
          show: true,
          lineStyle: {
            width: 1,
            color: "#ebebeb",
          },
        },
        axisLine: {
          show: false,
        },
        min: 'dataMin',
        max: 'dataMax',
        axisLabel: {
          textStyle: {
            color: "#666",
            fontSize: 14,
          },
        },
      },
    ],
    series: series,
  };
  if (iclear) {
    ele.clear();
  }
  ele.setOption(options, iclear);
};



const resize = () => {
  for (let key in chartObj) {
    if (chartObj[key].ele) {
      chartObj[key].ele.resize();
    }
  }
};

const onFileLoading = ref(false);

/**
 * 下载数据
 */
const handleDownload = async () => {
  downloadFile({
    sn: searchForm.value.sn,
    stime: format("yyyy-MM-dd hh:mm:ss", searchForm.value.timeRange[0]),
    etime: format("yyyy-MM-dd hh:mm:ss", searchForm.value.timeRange[1]),
  }).then((data) => {
    if (data.process === 1) {
      onDownload(data.url);
    } else if (data.process === 0) {
      onFileLoading.value = true;
      setTimeout(() => {
        handleDownload();
      }, 2000);
    } else if (data.process === -1) {
      onFileLoading.value = false;
      ElMessage.warning(data.msg || "下载失败，请重试");
    }
  });
};

let onDayLoading = ref(false);
/**
 * 按天打包下载
 */
const handlerDayDownload = () => {
  downloadDay({
    sn: searchForm.value.sn,
    time: searchForm.value.downloadDay,
  }).then((data) => {
    if (data.process === 1) {
      //
      onDownload(data.url);
    } else if (data.process === 0) {
      onDayLoading.value = true;
      setTimeout(() => {
        handlerDayDownload();
      }, 2000);
    } else if (data.process === -1) {
      onDayLoading.value = false;
      ElMessage.warning(data.msg || "下载失败，请重试");
    }
  });
};

const onDownload = (url) => {
  // 创建临时链接
  const a = document.createElement("a");
  a.href = url;
  // a.download = fileName;
  a.style.display = "none";

  // 添加到文档并触发点击
  document.body.appendChild(a);
  a.click();

  // 清理
  setTimeout(() => {
    document.body.removeChild(a);
    onDayLoading.value = false;
    onFileLoading.value = false;
  }, 100);
};
</script>

<style scoped lang="scss">
.filterArea {
  display: flex;
  justify-content: space-between;
  padding-top: 10px;

  .block {
    margin-right: 20px;
  }
}

.container {
  /* 容器样式 */
  display: flex;
  flex-direction: column;
  flex: 1;
  min-height: 0;
}

.lineChart {
  margin: 20px 0;
  width: 100%;
  height: 320px;
}
</style>
